﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Collections.Generic;
using System.Diagnostics;

namespace block_explorer
{
    class EntityDriver : IComponent
    {
        private BlockExplorer mGame;
        private BaseEntity mTarget;

        private const float HMouseSensitivity = 0.65f;
        private const float VMouseSensitivity = 0.65f;

        private MouseState mLastMouseState;

        public BaseEntity Target
        {
            get
            {
                return mTarget;
            }
            set
            {
                mTarget = value;
            }
        }

        public EntityDriver(BlockExplorer game)
        {
            mGame = game;
        }

        public void Initialize(GraphicsDevice device, ContentManager content)
        {
            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.W, KeyEvent.EventType.Pressed), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveForward, InputCommand.ContinuousEvent.Start)); });
            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.W, KeyEvent.EventType.Released), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveForward, InputCommand.ContinuousEvent.Stop)); });

            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.A, KeyEvent.EventType.Pressed), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveLeft, InputCommand.ContinuousEvent.Start)); });
            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.A, KeyEvent.EventType.Released), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveLeft, InputCommand.ContinuousEvent.Stop)); });

            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.S, KeyEvent.EventType.Pressed), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveBackward, InputCommand.ContinuousEvent.Start)); });
            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.S, KeyEvent.EventType.Released), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveBackward, InputCommand.ContinuousEvent.Stop)); });

            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.D, KeyEvent.EventType.Pressed), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveRight, InputCommand.ContinuousEvent.Start)); });
            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.D, KeyEvent.EventType.Released), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveRight, InputCommand.ContinuousEvent.Stop)); });

            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.Space, KeyEvent.EventType.Pressed), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveUp, InputCommand.ContinuousEvent.Start)); });
            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.Space, KeyEvent.EventType.Released), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveUp, InputCommand.ContinuousEvent.Stop)); });

            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.LeftShift, KeyEvent.EventType.Pressed), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveDown, InputCommand.ContinuousEvent.Start)); });
            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.LeftShift, KeyEvent.EventType.Released), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveDown, InputCommand.ContinuousEvent.Stop)); });

            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.LeftShift, KeyEvent.EventType.Pressed), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveDown, InputCommand.ContinuousEvent.Start)); });
            mGame.Input.RegisterKeyEvent(new KeyEvent(Keys.LeftShift, KeyEvent.EventType.Released), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.MoveDown, InputCommand.ContinuousEvent.Stop)); });

            mGame.Input.RegisterMouseButtonEvent(new MouseButtonEvent(MouseButtonEvent.Buttons.Left, MouseButtonEvent.EventType.Pressed), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.BlockPick, InputCommand.ContinuousEvent.NonContinuous)); });
            mGame.Input.RegisterMouseButtonEvent(new MouseButtonEvent(MouseButtonEvent.Buttons.Right, MouseButtonEvent.EventType.Pressed), delegate { Target.OnInputCommand(new InputCommand(InputCommand.Command.BlockPlace, InputCommand.ContinuousEvent.NonContinuous)); });
        }

        public void Destroy()
        {
        }

        public void Update(GameTime gameTime)
        {
            if (Target != null)
            {
                UpdateMouseState();
            }
        }

        private void UpdateMouseState()
        {
            // shouldnt call this unless we have a valid entity
            Debug.Assert(Target != null);

            Rectangle clientBounds = mGame.Window.ClientBounds;
            MouseState currentMouseState = Mouse.GetState();

            int centerX = clientBounds.Width / 2;
            int centerY = clientBounds.Height / 2;
            int deltaX = centerX - currentMouseState.X;
            int deltaY = centerY - currentMouseState.Y;

            Mouse.SetPosition(centerX, centerY);
            Target.Rotate(deltaX * HMouseSensitivity, deltaY * VMouseSensitivity);

            mLastMouseState = currentMouseState;
        }
    }
}
